//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
/*-------------------------------------------------------------------------
 * Filename:      serial.c
 * Version:       $Id: ftuart.c,v 1.1 2006/07/13 08:10:59 zhangyi Exp $
 * Copyright:     Copyright (C) 1999, Erik Mouw
 * Author:        Erik Mouw <J.A.K.Mouw@its.tudelft.nl>
 * Description:   Serial utilities for blob
 * Created at:    Tue Aug 24 20:25:00 1999
 * Modified by:   Erik Mouw <J.A.K.Mouw@its.tudelft.nl>
 * Modified at:   Mon Oct  4 20:11:14 1999
 *-----------------------------------------------------------------------*/
/*
 * serial.c: Serial utilities for blob
 *
 * Copyright (C) 1999  Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include "config.h"
#include "bulverde.h"
#include "time.h"
#include "ftuart.h"
#include "udelay.h"
/* number of nibbles in a word */
#define NIBBLES_PER_WORD (8)

/*
 * Initialise the serial port with the given baudrate. The settings
 * are always 8 data bits, no parity, 1 stop bit, no start bits.
 *
 */
void ftuart_init(eBauds baudrate)
{
    int value;

    __REG(CLK_BASE_PHYSICAL+CKEN_OFFSET) |= CKEN6_FFUART;
    //clear
    FFIER = 0;
    FFFCR = 0;
    FFLCR = 0;
    FFMCR = 0;
    FFISR = 0;

    FFFCR = 0X07;  /* enable FIFO,clear Rx FIFO and Tx FIFO */
      /* set baud rate */
    FFLCR = LCR_WLS0 | LCR_WLS1 | LCR_DLAB;
    FFDLL = baudrate & 0xff;
    FFDLH = baudrate >> 8;

    FFLCR = LCR_WLS0 | LCR_WLS1;
    FFIER = IER_UUE;  /* Enable BTUART */
    FFMCR = MCR_RTS;  /* Auto-RTS Enable*/
}

/*
 * Output a single byte to the BT-serial port.
 */
void ftuart_output_byte(const char c)
{

  /* wait for room in the tx FIFO on BTUART */
    while(( __REG(FFUART_BASE_PHYSICAL+FF_LSR_OFFSET) & LSR_TEMT) == 0) {
        ;
    }
    __REG(FFUART_BASE_PHYSICAL+FF_THR_OFFSET) = c;
}

/*
 * Output a single byte to the BT-serial port.
 */
void ftuart_output_rawbyte(const char c)
{
  /* wait for room in the tx FIFO on BTUART */
    while(( __REG(FFUART_BASE_PHYSICAL+FF_LSR_OFFSET) & LSR_TEMT) == 0) {
        ;
    }
    __REG(FFUART_BASE_PHYSICAL+FF_THR_OFFSET) = c;
}

void ftuart_output_byteinhex(const char c)
{
    char d;

    d = (char)((c >> 4) & 0x0f);
    if (d > 9)
        d += ('A' - 10);
    else
        d += '0';
    buart_output_byte(d);

    d = (char)(c & 0x0f);
    if (d > 9)
        d += ('A' - 10);
    else
        d += '0';
    ftuart_output_byte(d);
}

/*
 * Write a null terminated string to the serial port.
 */
void ftuart_output_string(const char *s)
{
    while (*s != 0) {
        ftuart_output_byte(*s++);
    }
}

/*
 * Write the argument of the function in hexadecimal to the serial
 * port. If you want "0x" in front of it, you'll have to add it
 * yourself.
 */
void ftuart_output_hex(const u32 h)
{
    char c;
    int i;

    for (i = NIBBLES_PER_WORD - 1; i >= 0; i--) {
        c = (char)((h >> (i * 4)) & 0x0f);

        if (c > 9)
            c += ('A' - 10);
        else
            c += '0';

        ftuart_output_byte(c);
    }
}

/*
 * Write the argument of the function in decimal to the serial port.
 * We just assume that each argument is positive (i.e. unsigned).
 */
void ftuart_output_dec(const u32 d)
{
    int leading_zero = 1;
    u32 divisor, result, remainder;

    remainder = d;

    for (divisor = 1000000000;
        divisor > 0;
        divisor /= 10) {
        result = remainder / divisor;
        remainder %= divisor;

        if (result != 0 || divisor == 1)
            leading_zero = 0;

        if (leading_zero == 0)
            ftuart_output_byte((char)(result) + '0');
    }
}

/*
 * Write a block of data to the serial port. Similar to
 * SerialOutputString(), but this function just writes the number of
 * characters indicated by bufsize and doesn't look at termination
 * characters.
 */
void ftuart_output_block(const char *buf, int bufsize)
{
    while (bufsize--)
        ftuart_output_byte(*buf++);
}

/*
 * Read a single byte from the serial port. Returns 1 on success, 0
 * otherwise. When the function is succesfull, the character read is
 * written into its argument c.
 */
int ftuart_input_str(char *buf, int count)
{
    int i;

    for (i = 0; i < count; i++) {
        while ((__REG(FFUART_BASE_PHYSICAL + FF_LSR_OFFSET) & LSR_DR) == 0)
            udelay(1);
        buf[i] = __REG(FFUART_BASE_PHYSICAL+FF_RBR_OFFSET) & 0xff;
    }
    return(1);
} /* SerialInputByte */

/*
 * Read a single byte from the serial port. Returns 1 on success, 0
 * otherwise. When the function is succesfull, the character read is
 * written into its argument c.
 */
int ftuart_input_byte(char *c)
{
    int count = 1000;

    while (((__REG(FFUART_BASE_PHYSICAL + FF_LSR_OFFSET) & LSR_DR) == 0) && (--count > 0))
        udelay(1);
    if (count > 0) {
        *c = __REG(FFUART_BASE_PHYSICAL+FF_RBR_OFFSET) & 0xff;
        return 1;
    }
    else {
        *c = 0;
        return 0;
    }
} /* SerialInputByte */

/*
 * read a string with maximum length len from the serial port
 * using a timeout of timeout seconds
 *
 * len is the length of array s _including_ the trailing zero,
 * the function returns the number of bytes read _excluding_
 * the trailing zero
 */
int  ftuart_input_string(char *s, const int len, const int timeout)
{
    u32 startTime, currentTime;
    char c;
    int i;
    int numRead;
    int skipNewline = 1;
    int maxRead = len - 1;

    startTime = TimerGetTime();

    for (numRead = 0, i = 0; numRead < maxRead;) {
        /* try to get a byte from the serial port */
        while (!ftuart_input_byte(&c)) {
            currentTime = TimerGetTime();

            /* check timeout value */
            if ((currentTime - startTime) > timeout) {
                /* timeout */
                s[i++] = '\0';
                return(numRead);
            }
        }
        startTime = TimerGetTime();
        /* eat newline characters at start of string */
        if ((skipNewline == 1) && (c != '\r') && (c != '\n'))
            skipNewline = 0;

        if (skipNewline == 0) {
            if ((c == '\r') || (c == '\n')) {
                s[i++] = '\0';
                return(numRead);
            }
            else {
                s[i++] = c;
                numRead++;
            }
        }
    }

    return(numRead);
}

/* 
 * SerialInputBlock(): almost the same as SerialInputString(), but
 * this one just reads a block of characters without looking at
 * special characters.
 */
int ftuart_clear_rx(void)
{
        // Clear the Rx FIFO
    __REG(FFUART_BASE_PHYSICAL+FF_FCR_OFFSET) = FCR_TRFIFOE | FCR_RESETRF;
}

int  ftuart_input_block(char *buf, int bufsize, const int timeout)
{
    u32 startTime, currentTime;
    char c;
    int i;
    int numRead;
    int maxRead = bufsize;

    startTime = TimerGetTime();

    for (numRead = 0, i = 0; numRead < maxRead) {
      /* try to get a byte from the serial port */
        while (!ftuart_input_byte(&c)) {
            currentTime = TimerGetTime();

            /* check timeout value */
            if ((currentTime - startTime) > timeout) {
                /* timeout! */
                return(numRead);
            }
        }
        startTime = TimerGetTime();
        buf[i++] = c;
        numRead ++;
    }

    return(numRead);
}

void ftuart_input_flush(void)
{
    volatile unsigned int ch;
    while ((__REG(FFUART_BASE_PHYSICAL + FF_LSR_OFFSET) & LSR_DR) != 0) {
        ch = __REG(FFUART_BASE_PHYSICAL+FF_LSR_OFFSET);
    }
    return;
}
